"""
Dify API集成服务
"""
import httpx
import json
import logging
import asyncio
from typing import Dict, Any, Optional, AsyncGenerator, List
from app.core.config import settings

logger = logging.getLogger(__name__)

class DifyService:
    """Dify API服务类"""
    
    def __init__(self):
        self.api_key = settings.DIFY_API_KEY
        self.base_url = settings.DIFY_BASE_URL
        self.headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
            "Accept": "*/*",
            "User-Agent": "EnterpriseAdminSystem/1.0"
        }
        logger.info(f"Dify服务初始化: API_KEY={self.api_key[:4]}***{self.api_key[-4:] if len(self.api_key) > 8 else ''}, BASE_URL={self.base_url}")
    
    def _validate_stream_data(self, data: Dict[str, Any], event_type: str) -> bool:
        """
        验证流式数据的完整性
        
        Args:
            data: 流式数据
            event_type: 事件类型
            
        Returns:
            验证结果
        """
        try:
            # 基本结构验证
            if not isinstance(data, dict):
                return False
            
            # 根据事件类型进行特定验证
            if event_type == 'message':
                # message 事件必须包含 answer 字段
                return 'answer' in data
            elif event_type == 'message_end':
                # message_end 事件必须包含完整的消息信息
                required_fields = ['id', 'conversation_id']
                return all(field in data for field in required_fields)
            elif event_type == 'workflow_started':
                # workflow_started 事件验证
                return 'workflow_run_id' in data
            elif event_type == 'node_started':
                # node_started 事件验证
                return 'node_id' in data
            elif event_type == 'error':
                # error 事件必须包含错误信息
                return 'message' in data or 'error' in data
            
            # 其他事件类型默认通过验证
            return True
            
        except Exception as e:
            logger.warning(f"数据验证异常: {e}")
            return False
    
    async def send_message(
        self, 
        message: str, 
        user_id: str,
        conversation_id: Optional[str] = None,
        files: Optional[List[Dict[str, Any]]] = None
    ) -> Dict[str, Any]:
        """
        发送消息到Dify API
        
        Args:
            message: 用户消息
            user_id: 用户ID
            conversation_id: 会话ID（可选）
            files: 附件列表（可选）
            
        Returns:
            Dify API响应
        """
        try:
            url = f"{self.base_url}/chat-messages"
            
            # 构建与Postman示例一致的请求体
            payload = {
                "inputs": {
                    "errorinfo": ""  # 根据示例添加空的errorinfo字段
                },
                "query": message,
                "response_mode": "blocking",  # 修改为blocking模式，而不是streaming
                "user": user_id,
                "files": files or []
            }
            
            # 如果有会话ID，添加到请求中
            if conversation_id:
                logger.info(f"使用现有会话ID: {conversation_id}")
                payload["conversation_id"] = conversation_id
            else:
                logger.info("创建新会话，使用空字符串作为conversation_id")
                payload["conversation_id"] = ""  # 根据示例，新会话使用空字符串

            logger.info(f"发送到 Dify 的请求: URL={url}")
            logger.debug(f"请求头: {json.dumps({k: v for k, v in self.headers.items() if k != 'Authorization'})}")
            logger.debug(f"请求体: {json.dumps(payload, ensure_ascii=False)}")
            
            async with httpx.AsyncClient() as client:
                try:
                    response = await client.post(
                        url,
                        headers=self.headers,
                        json=payload,
                        timeout=600.0  # 设置为10分钟超时
                    )
                    
                    logger.info(f"收到 Dify 的响应: Status={response.status_code}")
                    
                    # 记录响应内容，但避免日志过大
                    if len(response.text) > 1000:
                        logger.debug(f"响应内容(截断): {response.text[:1000]}...")
                    else:
                        logger.debug(f"响应内容: {response.text}")
                        
                except Exception as e:
                    logger.error(f"发送请求时发生异常: {str(e)}")
                    raise
                
                if response.status_code == 200:
                    try:
                        result = response.json()
                        logger.info(f"Dify API调用成功: message_id={result.get('message_id', 'unknown')}, conversation_id={result.get('conversation_id', 'unknown')}")
                        
                        # 确保返回结构与示例一致
                        return {
                            "success": True,
                            "data": {
                                "id": result.get("id", ""),
                                "message_id": result.get("message_id", ""),
                                "conversation_id": result.get("conversation_id", ""),
                                "answer": result.get("answer", ""),
                                "metadata": result.get("metadata", {}),
                                "created_at": result.get("created_at", 0)
                            },
                            "message": "消息发送成功"
                        }
                    except json.JSONDecodeError:
                        # 如果响应不是JSON格式，可能是SSE格式，尝试解析最后一个消息
                        logger.warning("响应不是JSON格式，尝试解析SSE格式")
                        
                        # 解析SSE格式的响应
                        last_data = None
                        message_id = None
                        conversation_id = None
                        answer = ""
                        
                        for line in response.text.split('\n'):
                            if line.startswith('data: '):
                                data_str = line[6:]
                                if data_str == '[DONE]':
                                    continue
                                    
                                try:
                                    data = json.loads(data_str)
                                    last_data = data
                                    
                                    # 提取消息ID和会话ID
                                    if 'message_id' in data:
                                        message_id = data['message_id']
                                    if 'conversation_id' in data:
                                        conversation_id = data['conversation_id']
                                    
                                    # 如果是消息事件，累加答案内容
                                    if data.get('event') == 'message' and 'answer' in data:
                                        answer += data['answer']
                                except:
                                    continue
                        
                        if last_data:
                            logger.info(f"从SSE响应中提取数据: message_id={message_id}, conversation_id={conversation_id}")
                            return {
                                "success": True,
                                "data": {
                                    "id": message_id or "",
                                    "message_id": message_id or "",
                                    "conversation_id": conversation_id or "",
                                    "answer": answer,
                                    "metadata": last_data.get("metadata", {}),
                                    "created_at": last_data.get("created_at", 0)
                                },
                                "message": "消息发送成功(从SSE响应解析)"
                            }
                        else:
                            logger.error("无法从SSE响应中提取有效数据")
                            return {
                                "success": False,
                                "error": "无法解析响应",
                                "message": "无法从响应中提取有效数据",
                                "response_text": response.text[:1000] if len(response.text) > 1000 else response.text
                            }
                else:
                    error_text = response.text
                    try:
                        error_json = response.json()
                        error_detail = error_json.get('error', {}).get('message', error_text)
                    except:
                        error_detail = error_text
                        
                    logger.error(f"Dify API调用失败: {response.status_code} - {error_detail}")
                    return {
                        "success": False,
                        "error": f"API调用失败: {response.status_code}",
                        "message": f"消息发送失败: {error_detail}",
                        "response_text": error_text[:1000] if len(error_text) > 1000 else error_text  # 添加原始响应文本以便调试
                    }
        except httpx.TimeoutException as e:
            logger.error(f"Dify API调用超时: {str(e)}")
            return {
                "success": False,
                "error": "请求超时",
                "message": "消息发送超时，请稍后重试",
                "exception": str(e)
            }
        except Exception as e:
            logger.error(f"Dify API调用异常: {str(e)}")
            return {
                "success": False,
                "error": str(e),
                "message": "消息发送失败，请稍后重试",
                "exception": str(e)
            }
    
    async def send_message_stream(
        self, 
        message: str, 
        user_id: str,
        conversation_id: Optional[str] = None,
        files: Optional[List[Dict[str, Any]]] = None,
        errorinfo: Optional[str] = None
    ) -> AsyncGenerator[Dict[str, Any], None]:
        """
        发送消息到Dify API并返回流式响应
        
        Args:
            message: 用户消息
            user_id: 用户ID
            conversation_id: 会话ID（可选）
            files: 附件列表（可选）
            
        Yields:
            流式响应数据
        """
        try:
            url = f"{self.base_url}/chat-messages"
            
            # 构建流式请求体
            payload = {
                "inputs": {
                    "errorinfo": errorinfo or ""
                },
                "query": message,
                "response_mode": "streaming",
                "user": user_id,
                "files": files or []
            }
            
            if conversation_id:
                payload["conversation_id"] = conversation_id
            else:
                payload["conversation_id"] = ""

            logger.info(f"发送流式请求到 Dify API: URL={url}")
            logger.debug(f"流式请求体: {json.dumps(payload, ensure_ascii=False)}")
            
            # 设置流式请求头
            stream_headers = self.headers.copy()
            stream_headers["Accept"] = "text/event-stream"
            
            async with httpx.AsyncClient(timeout=600.0) as client:
                async with client.stream(
                    "POST",
                    url,
                    headers=stream_headers,
                    json=payload
                ) as response:
                    
                    if response.status_code != 200:
                        error_text = await response.aread()
                        logger.error(f"流式请求失败: {response.status_code} - {error_text.decode()}")
                        yield {
                            "event": "error",
                            "data": {
                                "error": f"API调用失败: {response.status_code}",
                                "message": error_text.decode()[:500]
                            }
                        }
                        return
                    
                    logger.info("开始接收流式响应数据")
                    buffer = ""
                    
                    chunk_count = 0
                    last_activity = asyncio.get_event_loop().time()
                    heartbeat_interval = 30  # 30秒心跳检测
                    
                    async for chunk in response.aiter_text():
                        if not chunk:
                            # 检查是否超时无数据
                            current_time = asyncio.get_event_loop().time()
                            if current_time - last_activity > heartbeat_interval:
                                logger.warning("流式连接超时无数据，发送心跳")
                                yield {
                                    "event": "heartbeat",
                                    "data": {"timestamp": current_time, "message": "连接正常"}
                                }
                                last_activity = current_time
                            continue
                            
                        chunk_count += 1
                        last_activity = asyncio.get_event_loop().time()
                        
                        buffer += chunk
                        lines = buffer.split('\n')
                        buffer = lines[-1]  # 保留最后一行（可能不完整）
                        
                        for line in lines[:-1]:
                            line = line.strip()
                            if not line:
                                continue
                                
                            # 解析 SSE 格式数据
                            if line.startswith('data: '):
                                data_str = line[6:]  # 移除 'data: ' 前缀
                                
                                if data_str == '[DONE]':
                                    logger.info(f"流式响应完成，共处理 {chunk_count} 个数据块")
                                    yield {
                                        "event": "done",
                                        "data": {"message": "流式响应完成", "chunks_processed": chunk_count}
                                    }
                                    return
                                
                                try:
                                    data = json.loads(data_str)
                                    event_type = data.get('event', 'message')
                                    
                                    logger.debug(f"接收到流式事件: {event_type}")
                                    
                                    # 验证数据完整性
                                    if not self._validate_stream_data(data, event_type):
                                        logger.warning(f"流式数据验证失败: {event_type}")
                                        yield {
                                            "event": "warning",
                                            "data": {"message": f"数据验证失败: {event_type}", "raw_data": data}
                                        }
                                        continue
                                    
                                    # 根据事件类型处理数据
                                    if event_type == 'workflow_started':
                                        yield {
                                            "event": "workflow_started",
                                            "data": data
                                        }
                                    elif event_type == 'node_started':
                                        yield {
                                            "event": "node_started", 
                                            "data": data
                                        }
                                    elif event_type == 'message':
                                        yield {
                                            "event": "message",
                                            "data": data
                                        }
                                    elif event_type == 'message_end':
                                        yield {
                                            "event": "message_end",
                                            "data": data
                                        }
                                    elif event_type == 'error':
                                        logger.error(f"Dify API 返回错误事件: {data}")
                                        yield {
                                            "event": "error",
                                            "data": data
                                        }
                                        return  # 遇到错误事件时终止流
                                    else:
                                        # 处理其他类型的事件
                                        yield {
                                            "event": event_type,
                                            "data": data
                                        }
                                        
                                except json.JSONDecodeError as e:
                                    logger.warning(f"解析流式数据失败: {e}, 数据: {data_str[:100]}")
                                    yield {
                                        "event": "parse_error",
                                        "data": {
                                            "error": str(e),
                                            "raw_data": data_str[:200],
                                            "message": "数据解析失败，跳过此数据块"
                                        }
                                    }
                                    continue
                                except Exception as e:
                                    logger.error(f"处理流式数据时发生异常: {e}")
                                    yield {
                                        "event": "processing_error",
                                        "data": {
                                            "error": str(e),
                                            "message": "数据处理异常"
                                        }
                                    }
                                    continue
                                    
        except httpx.TimeoutException as e:
            logger.error(f"流式请求超时: {str(e)}")
            yield {
                "event": "error",
                "data": {
                    "error": "请求超时",
                    "message": "流式请求超时，请稍后重试"
                }
            }
        except Exception as e:
            logger.error(f"流式请求异常: {str(e)}")
            yield {
                "event": "error", 
                "data": {
                    "error": str(e),
                    "message": "流式请求失败，请稍后重试"
                }
            }

    async def get_conversation_messages(self, conversation_id: str) -> Dict[str, Any]:
        """
        获取会话消息历史
        
        Args:
            conversation_id: 会话ID
            
        Returns:
            会话消息列表
        """
        try:
            url = f"{self.base_url}/messages"
            params = {
                "conversation_id": conversation_id,
                "first_id": "",
                "limit": 20
            }
            
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    url,
                    headers=self.headers,
                    params=params,
                    timeout=10.0
                )
                
                if response.status_code == 200:
                    result = response.json()
                    return {
                        "success": True,
                        "data": result,
                        "message": "获取消息历史成功"
                    }
                else:
                    logger.error(f"获取消息历史失败: {response.status_code}")
                    return {
                        "success": False,
                        "error": f"API调用失败: {response.status_code}",
                        "message": "获取消息历史失败"
                    }
                    
        except Exception as e:
            logger.error(f"获取消息历史异常: {str(e)}")
            return {
                "success": False,
                "error": str(e),
                "message": "获取消息历史失败"
            }
    
    async def get_conversations(self, user_id: str) -> Dict[str, Any]:
        """
        获取用户的会话列表
        
        Args:
            user_id: 用户ID
            
        Returns:
            会话列表
        """
        try:
            url = f"{self.base_url}/conversations"
            params = {
                "user": user_id,
                "first_id": "",
                "limit": 20,
                "pinned": None
            }
            
            async with httpx.AsyncClient() as client:
                response = await client.get(
                    url,
                    headers=self.headers,
                    params=params,
                    timeout=10.0
                )
                
                if response.status_code == 200:
                    result = response.json()
                    return {
                        "success": True,
                        "data": result,
                        "message": "获取会话列表成功"
                    }
                else:
                    logger.error(f"获取会话列表失败: {response.status_code}")
                    return {
                        "success": False,
                        "error": f"API调用失败: {response.status_code}",
                        "message": "获取会话列表失败"
                    }
                    
        except Exception as e:
            logger.error(f"获取会话列表异常: {str(e)}")
            return {
                "success": False,
                "error": str(e),
                "message": "获取会话列表失败"
            }

# 创建全局实例
dify_service = DifyService()